package com.yu;


import com.yu.annotion.*;
import com.yu.bean.BeanDefinition;
import com.yu.commoninterface.ApplicationContextAware;
import com.yu.commoninterface.BeanFactory;
import com.yu.commoninterface.BeanPostProcessor;
import com.yu.commoninterface.InitializingBean;
import com.yu.processor.AspectProcessor;
import com.yu.processor.ScanProcessor;
import com.yu.util.ClassUtil;
import sun.security.util.ArrayUtil;

import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;


// ioc容器
public class ApplicationContext {

    private ScanProcessor scanProcessor;

    // 一级缓存 存放最终对象
    private Map<String, Object> singletonObjects = new ConcurrentHashMap<>();

    // 二级缓存 存放初始化还未完成属性赋值 提前暴露出来的对象(aop代理对象也在这里)
    private Map<String, Object> earlySingletonObjects = new HashMap<>();

    // 三级缓存 用于获取提前暴露的对象的函数式接口
    private Map<String, BeanFactory> singletonFactories = new HashMap<>();

    // 记录当前正在创建的Bean 依赖注入时使用 
    private Set<Object> currentCreatingBeans = new HashSet<>();

    // 所有bean的定义
    private Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>();

    // <方法全名, aop处理器>
    private Map<String, List<AspectProcessor>> aspectProcessorMap = new HashMap<>();
    private Set<Class> beanClassOfNeedAop = new HashSet<>(); // 需要代理的bean

    public ApplicationContext() {
    }

    // 从起始类开始扫描所有类
    public ApplicationContext(Class<?> clazz) {
        // 扫描所有包 生成BeanDefinitionMap
        scanProcessor = new ScanProcessor(clazz, beanDefinitionMap);

        // 关联并先创建所有要代理的方法和aop处理Bean
        for (BeanDefinition aspectBeanDefinition : scanProcessor.getAspectBeanDefinitions()) {
            for (Method aspectMethod : aspectBeanDefinition.getBeanClass().getDeclaredMethods()) {
                if (aspectMethod.isAnnotationPresent(Around.class)) {
                    Around around = aspectMethod.getAnnotation(Around.class);
                    beanClassOfNeedAop.add(around.targetClass());
                    for (String method : around.methods()) {
                        List<AspectProcessor> processors = aspectProcessorMap
                                .computeIfAbsent(around.targetClass().getTypeName() + "." + method, k -> new ArrayList<>());
                        processors.add(new AspectProcessor(getBeanByName(aspectBeanDefinition.getBeanName()), aspectMethod));
                    }
                }
            }
        }

        // 创建单例Bean
        for (BeanDefinition beanDefinition : beanDefinitionMap.values())
            if (beanDefinition.getScopeName() == ScopeName.ENUM_singleton)
                createBean(beanDefinition);
        System.out.println("[spring] 初始化完成");
        System.out.println("[spring] singletonObjects: " + singletonObjects);
        System.out.println("[spring] earlySingletonObjects: " + earlySingletonObjects);
        System.out.println("[spring] singletonFactories: " + singletonFactories);
        System.out.println("[spring] beanClassOfNeedAop: " + beanClassOfNeedAop);
        System.out.println("[spring] aspectProcessorMap: " + aspectProcessorMap);
    }


    // 创建Bean并进行依赖注入
    private Object createBean(BeanDefinition beanDefinition) {
        // TODO 从三个缓存中获取单例Bean
        Object singleBean = getSingleBean(beanDefinition.getBeanName());
        if (singleBean != null)
            return singleBean;

        // TODO 创建原始空对象 创建BeanFactory并存入到SingletonFactories里
        singleBean = doCreateBean(beanDefinition.getBeanName());

        // TODO 属性填充(依赖注入DI)
        Class<?> beanClass = beanDefinition.getBeanClass();
        Field[] fields = beanClass.getDeclaredFields();
        for (Field field : fields) {
            if (field.isAnnotationPresent(Autowired.class) || field.isAnnotationPresent(Resource.class)) {
                if (!beanDefinitionMap.containsKey(field.getName()))
                    throw new RuntimeException(beanDefinition.getBeanName() + "的依赖注入失败, 不存在Bean的定义: " + field.getName());

                field.setAccessible(true);
                Object fieldBean = getSingleBean(field.getName()); // 依赖的Bean
                if (fieldBean == null) { // 依赖的Bean还没创建出来或正在创建
                    if (currentCreatingBeans.contains(field.getName()) || beanDefinition.getScopeName() == ScopeName.ENUM_prototype)
                        throw new RuntimeException(beanDefinition.getBeanName() + "出现循环依赖 无法解决----");
                    fieldBean = createBean(beanDefinitionMap.get(field.getName())); // TODO 递归 先去创建完这个依赖Bean
                }
                try {
                    field.set(singleBean, fieldBean);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }

        // TODO 如果需要AppliationContext就注入ApplicationContext对象
        if (singleBean instanceof ApplicationContextAware) {
            try {
                ((ApplicationContextAware) singleBean).setApplicationContext(this);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        // TODO BeanPostProcessor的预初始化方法
        for (String beanPostProcessorBeanName : scanProcessor.getBeanPostProcessorBeanNames())
            singleBean = ((BeanPostProcessor) getBeanByName(beanPostProcessorBeanName)).postProcessBeforeInitialization(singleBean, beanDefinition.getBeanName());


        // TODO 调用自定义的初始化方法
        if (singleBean instanceof InitializingBean) {
            try {
                ((InitializingBean) singleBean).afterPropertiesSet();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        // TODO BeanPostProcessor的初始化后方法  aop代理也在这里生成
        for (String beanPostProcessorBeanName : scanProcessor.getBeanPostProcessorBeanNames())
            singleBean = ((BeanPostProcessor) getBeanByName(beanPostProcessorBeanName)).postProcessAfterInitialization(singleBean, beanDefinition.getBeanName());

        currentCreatingBeans.remove(beanDefinition.getBeanName());
        System.out.println("[spring]" + beanDefinition.getBeanName() + "创建完成, class对象为: " + singleBean.getClass());
        return singleBean;
    }

    // 从三个缓存里获取单例Bean
    private Object getSingleBean(String name) {
        Object o = singletonObjects.get(name);
        if (o == null) {
            o = earlySingletonObjects.get(name);
            if (o == null) {
                BeanFactory beanFactory = singletonFactories.get(name);
                if (beanFactory != null) {
                    earlySingletonObjects.put(name, o = beanFactory.getBean()); // 放到二级缓存里
                    singletonFactories.remove(name); // 从三级缓存里删除
                }
            }
        }
        return o;
    }

    // 生成默认的BeanFactory 提前暴露对象
    private BeanFactory generateDefaultBeanFactory(Object originEmptyObject, String beanName) {
        return () -> {
            // TODO 已经提前Aop代理过了
            if (earlySingletonObjects.containsKey(beanName))
                return earlySingletonObjects.get(beanName);

            // TODO 移除3级缓存 提前代理、暴露对象
            singletonFactories.remove(beanName); // 移除3级缓存
            Object aopBean = wrapperBeanToAopIfNecessary(originEmptyObject, beanName);
            earlySingletonObjects.put(beanName, aopBean);
            return aopBean;
        };
    }

    // TODO 创建原始空对象 创建BeanFactory并存入到SingletonFactories三级缓存里
    private Object doCreateBean(String beanName) {
        try {
            Object originEmptyObject = beanDefinitionMap.get(beanName).getBeanClass().newInstance();
            currentCreatingBeans.add(beanName); // 标记正在创建中
            // TODO 根据原生对象创建BeanFactory并放到第三级缓存里
            singletonFactories.put(beanName, generateDefaultBeanFactory(originEmptyObject, beanName));
            return originEmptyObject;
        } catch (InstantiationException | IllegalAccessException e) {
            throw new RuntimeException("无法创建Bean: " + beanName, e);
        }
    }

    public Object getBeanByName(String name) {
        BeanDefinition beanDefinition = beanDefinitionMap.get(name);
        if (beanDefinition == null)
            return null;

        // 多例Bean
        if (beanDefinition.getScopeName() == ScopeName.ENUM_prototype) {
            try {
                return beanDefinition.getBeanClass().newInstance();
            } catch (InstantiationException | IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        // 从IOC容器中取 没有就创建
        Object o = singletonObjects.get(name);
        return o == null ? createBean(beanDefinition) : o;
    }

    // 将对象转换成AOP代理对象
    public Object wrapperBeanToAopIfNecessary(Object bean, String beanName) {
        if (!beanClassOfNeedAop.contains(bean.getClass())) // 不需要代理
            return bean;

        Class<?>[] interfaces = bean.getClass().getInterfaces(); // 被代理类的接口
        if (interfaces.length > 0) {
            System.out.println("[Spring] 对" + beanName + "类  " + "进行增强");
            // TODO 本质: 创建jdk动态代理对象 (原理: 生成一个实现了所有接口的实现类)
            return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), interfaces, new AopProxyHandle(bean));
        } else {
            throw new RuntimeException("[Spring] " + beanName + "类" + "无法增强  只支持接口代理");
        }
    }

    // TODO AOP代理类的Handler处理器
    private class AopProxyHandle implements InvocationHandler {
        private final Object realObject; // 被代理的真实对象

        public AopProxyHandle(Object target) {
            this.realObject = target;
        }

        // 代理执行对象的每个方法
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            List<AspectProcessor> processors = aspectProcessorMap.get(realObject.getClass().getTypeName() + "." + method.getName());
            if (processors == null) // 该方法不需要Aop增强，直接代理执行
                return method.invoke(realObject, args);
            Object returnResult = null;
            // 将方法执行权交给用户
            for (AspectProcessor processor : processors)
                returnResult = processor.getAspectMethod().invoke(processor.getAspectBean(), realObject, method, args);
            return returnResult;
        }
    }

    public ScanProcessor getScanProcessor() {
        return scanProcessor;
    }

    public Map<String, Object> getSingletonObjects() {
        return singletonObjects;
    }

    public Map<String, Object> getEarlySingletonObjects() {
        return earlySingletonObjects;
    }

    public Map<String, BeanFactory> getSingletonFactories() {
        return singletonFactories;
    }

    public Set<Object> getCurrentCreatingBeans() {
        return currentCreatingBeans;
    }

    public Map<String, BeanDefinition> getBeanDefinitionMap() {
        return beanDefinitionMap;
    }

    public Map<String, List<AspectProcessor>> getAspectProcessorMap() {
        return aspectProcessorMap;
    }

    public Set<Class> getBeanClassOfNeedAop() {
        return beanClassOfNeedAop;
    }
}
